using System;
using System.Collections.Generic;
using NUnit.Framework;
using OpenViewer.Framework;

namespace Mogre.Tests
{
  public class MogreTestBase : IOgreControl
  {
    private string m_rendersys = "OpenGL Rendering Subsystem";
    private Root mRoot;
    private float ticks;
    private RenderWindow mWindow;

    protected void Setup()
    {
      //the order of these is important
      CreateRoot();
      SetupRenderSystem();
      DefineResources();
      CreateRenderWindow();
      InitResources();
      CreateScene();
    }

    protected void Go()
    {
      StartRenderLoop();
    }

    private void CreateRoot()
    {
      mRoot = new Root(String.Format("plugins-{0}.cfg", Util.GetOS()));
    }

    private void DefineResources()
    {
      ConfigFile cf = new ConfigFile();
      cf.Load("resources.cfg", "\t:=", true);

      // Go through all sections & settings in the file
      ConfigFile.SectionIterator section = cf.GetSectionIterator();

      String secName, typeName, archName;

      // Normally we would use the foreach syntax, which enumerates the values, but in this case we need CurrentKey too;
      while (section.MoveNext())
      {
        secName = section.CurrentKey;
        ConfigFile.SettingsMultiMap settings = section.Current;
        foreach (KeyValuePair<string, string> pair in settings)
        {
          typeName = pair.Key;
          archName = pair.Value;
          ResourceGroupManager.Singleton.AddResourceLocation(archName, typeName, secName);
        }
      }
    }

    private void SetupRenderSystem()
    {
      foreach (RenderSystem rs in mRoot.GetAvailableRenderers())
      {
        if (rs.Name == m_rendersys)
        {
          mRoot.RenderSystem = rs;
          break;
        }
      }

      if (mRoot.RenderSystem == null)
      {
        throw new Exception(String.Format("Render system \"{0}\" not found", m_rendersys));
      }

      mRoot.RenderSystem.SetConfigOption("Full Screen", "No");
      mRoot.RenderSystem.SetConfigOption("Video Mode", "800 x 600@ 32-bit colour");
    }

    private void CreateRenderWindow()
    {
      mWindow = mRoot.Initialise(true, "Main Ogre Window");
    }

    private void CreateRenderWindowInControl(IntPtr handle)
    {
      // Create Render Window
      mRoot.Initialise(false, "Main Ogre Window");
      NameValuePairList misc = new NameValuePairList();
      misc["externalWindowHandle"] = handle.ToString();
      mWindow = mRoot.CreateRenderWindow("Main RenderWindow", 800, 600, false, misc);
    }

    private void InitResources()
    {
      TextureManager.Singleton.DefaultNumMipmaps = 6;
      ResourceGroupManager.Singleton.InitialiseAllResourceGroups();
    }

    private void CreateScene()
    {
      SceneManager mgr = mRoot.CreateSceneManager(SceneType.ST_GENERIC);
      Camera cam = mgr.CreateCamera("Camera");
      cam.AutoAspectRatio = true;
      mWindow.AddViewport(cam);

      Entity ent = mgr.CreateEntity("ninja", "ninja.mesh");
      mgr.RootSceneNode.CreateChildSceneNode().AttachObject(ent);

      cam.Position = new Vector3(0, 200, -400);
      cam.LookAt(ent.BoundingBox.Center);

      mRoot.FrameEnded += new FrameListener.FrameEndedHandler(FrameEnded);
      ticks = Environment.TickCount;
    }

    private void StartRenderLoop()
    {
      mRoot.StartRendering();

      //// Alternate Rendering Loop
      //while (mRoot.RenderOneFrame())
      //{
      //    // Do other things here, such as sleep for a short period of time
      //}
    }

    private bool FrameEnded(FrameEvent evt)
    {
      return true;
    }

    public void OgreForm_Resize(object sender, EventArgs e)
    {
      mWindow.WindowMovedOrResized();
    }

    public void OgreForm_Disposed(object sender, EventArgs e)
    {
      mRoot.Dispose();
      mRoot = null;
    }

    public void Init(IntPtr handle)
    {
      CreateRoot();
      SetupRenderSystem();
      DefineResources();
      CreateRenderWindowInControl(handle);
      InitResources();
      CreateScene();
    }

    public bool RunOneFrame()
    {
      if(mRoot != null && mRoot.RenderOneFrame())
      {
        return true;
      }
      return false;
    }
  }
}